package com.ittao.taoaicodeapp.service.impl;

import com.ittao.taoaicodeai.ai.config.VipLimitConfig;
import com.ittao.taoaicodeapp.service.VipLimitService;
import com.ittao.taoaicodecommon.exception.BusinessException;
import com.ittao.taoaicodecommon.exception.ErrorCode;
import com.ittao.taoaicodemodel.model.entity.User;
import com.ittao.taoaicodemodel.model.enums.UserRoleEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * VIP 限制服务
 */
@Service
@Slf4j
public class VipLimitServiceImpl implements VipLimitService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private VipLimitConfig vipLimitConfig;

    // 统一的Redis Key前缀，基于用户ID存储
    private static final String USER_LIMITS_KEY_PREFIX = "user_limits:";
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    // Hash字段名称
    private static final String FIELD_APP_GEN_COUNT = "appGenCount";
    private static final String FIELD_DOWNLOAD_COUNT = "downloadCount";
    private static final String FIELD_EXPORT_COUNT = "exportCount";
    private static final String FIELD_DATE = "date";
    private static final String FIELD_USER_ROLE = "userRole";

    /**
     * 检查并递增每日应用生成次数
     *
     * @param user 用户
     * @throws BusinessException 如果超出限制
     */
    @Override
    public void checkAndIncrementDailyAppGen(User user) {
        String userRole = user.getUserRole();
        UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(userRole);
        VipLimitConfig.UserLimits limits = vipLimitConfig.getLimitsByRole(userRole);
        int dailyLimit = limits.getDailyAppGen();

        // 管理员和无限制的情况直接放行
        if (UserRoleEnum.ADMIN.equals(userRoleEnum) || dailyLimit == -1) {
            return;
        }

        Map<String, Integer> userLimits = getUserDailyLimits(user);
        int currentCount = userLimits.get(FIELD_APP_GEN_COUNT);

        if (currentCount >= dailyLimit) {
            throw new BusinessException(ErrorCode.DAILY_LIMIT_EXCEEDED);
        }

        // 递增计数器
        int newCount = incrementUserLimit(user, FIELD_APP_GEN_COUNT);
        log.info("用户 {} 今日应用生成次数: {}/{}", user.getId(), newCount, dailyLimit);
    }

    /**
     * 检查并递增每日下载代码次数
     *
     * @param user 用户
     * @throws BusinessException 如果超出限制
     */
    @Override
    public void checkAndIncrementDailyDownload(User user) {
        String userRole = user.getUserRole();
        UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(userRole);
        VipLimitConfig.UserLimits limits = vipLimitConfig.getLimitsByRole(userRole);
        int dailyLimit = limits.getDailyDownload();

        // VIP用户和管理员无限制下载
        if (UserRoleEnum.VIP.equals(userRoleEnum) || UserRoleEnum.ADMIN.equals(userRoleEnum) || dailyLimit == -1) {
            return;
        }

        Map<String, Integer> userLimits = getUserDailyLimits(user);
        int currentCount = userLimits.get(FIELD_DOWNLOAD_COUNT);

        if (currentCount >= dailyLimit) {
            throw new BusinessException(ErrorCode.VIP_REQUIRED_FOR_DOWNLOAD);
        }

        // 递增计数器
        int newCount = incrementUserLimit(user, FIELD_DOWNLOAD_COUNT);
        log.info("用户 {} 今日下载次数: {}/{}", user.getId(), newCount, dailyLimit);
    }

    /**
     * 检查并递增每日导出次数
     */
    @Override
    public void checkAndIncrementDailyExport(User user) {
        String userRole = user.getUserRole();
        UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(userRole);
        VipLimitConfig.UserLimits limits = vipLimitConfig.getLimitsByRole(userRole);
        int dailyLimit = limits.getDailyExport();

        // VIP用户和管理员无限制导出
        if (UserRoleEnum.VIP.equals(userRoleEnum) || UserRoleEnum.ADMIN.equals(userRoleEnum) || dailyLimit == -1) {
            return;
        }

        Map<String, Integer> userLimits = getUserDailyLimits(user);
        int currentCount = userLimits.get(FIELD_EXPORT_COUNT);

        if (currentCount >= dailyLimit) {
            throw new BusinessException(ErrorCode.VIP_REQUIRED_FOR_EXPORT);
        }

        // 递增计数器
        int newCount = incrementUserLimit(user, FIELD_EXPORT_COUNT);
        log.info("用户 {} 今日导出次数: {}/{}", user.getId(), newCount, dailyLimit);
    }

    /**
     * 获取用户的最大Token数量配置
     */
    @Override
    public int getMaxTokens(User user) {
        VipLimitConfig.UserLimits limits = vipLimitConfig.getLimitsByRole(user.getUserRole());
        return limits.getMaxTokens();
    }

    /**
     * 获取用户的最大消息记忆条数配置
     */
    @Override
    public int getMaxMessages(User user) {
        VipLimitConfig.UserLimits limits = vipLimitConfig.getLimitsByRole(user.getUserRole());
        return limits.getMaxMessages();
    }

    /**
     * 检查Token数量是否超限
     */
    @Override
    public void checkTokenLimit(User user, int tokenCount) {
        int maxTokens = getMaxTokens(user);
        if (tokenCount > maxTokens) {
            throw new BusinessException(ErrorCode.TOKEN_LIMIT_EXCEEDED);
        }
    }

    /**
     * 获取用户今日剩余次数信息
     */
    @Override
    public String getRemainingLimitsInfo(User user) {
        String userRole = user.getUserRole();
        UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(userRole);
        VipLimitConfig.UserLimits limits = vipLimitConfig.getLimitsByRole(userRole);

        Map<String, Integer> userLimits = getUserDailyLimits(user);

        StringBuilder info = new StringBuilder();
        info.append("用户限制信息: ");

        // 应用生成限制
        int appGenLimit = limits.getDailyAppGen();
        int appGenUsed = userLimits.get(FIELD_APP_GEN_COUNT);
        if (UserRoleEnum.ADMIN.equals(userRoleEnum) || appGenLimit == -1) {
            info.append("应用生成: 无限制, ");
        } else {
            info.append("应用生成: ").append(appGenUsed).append("/").append(appGenLimit).append(", ");
        }

        // 下载限制
        int downloadLimit = limits.getDailyDownload();
        int downloadUsed = userLimits.get(FIELD_DOWNLOAD_COUNT);
        if (UserRoleEnum.VIP.equals(userRoleEnum) || UserRoleEnum.ADMIN.equals(userRoleEnum) || downloadLimit == -1) {
            info.append("下载: 无限制, ");
        } else {
            info.append("下载: ").append(downloadUsed).append("/").append(downloadLimit).append(", ");
        }

        // 导出限制
        int exportLimit = limits.getDailyExport();
        int exportUsed = userLimits.get(FIELD_EXPORT_COUNT);
        if (UserRoleEnum.VIP.equals(userRoleEnum) || UserRoleEnum.ADMIN.equals(userRoleEnum) || exportLimit == -1) {
            info.append("导出: 无限制");
        } else {
            info.append("导出: ").append(exportUsed).append("/").append(exportLimit);
        }

        return info.toString();
    }

    /**
     * 获取用户今日限制使用情况
     * 统一从Redis Hash中获取所有限制数据
     */
    private Map<String, Integer> getUserDailyLimits(User user) {
        String today = LocalDate.now().format(DATE_FORMATTER);
        String userKey = buildUserLimitsKey(user.getId());

        HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();

        // 检查是否为今天的数据
        String storedDate = hashOps.get(userKey, FIELD_DATE);
        String storedRole = hashOps.get(userKey, FIELD_USER_ROLE);

        Map<String, Integer> limits = new HashMap<>();

        // 如果日期不匹配或用户角色变更，重置数据
        if (!today.equals(storedDate) || !user.getUserRole().equals(storedRole)) {
            resetUserDailyLimits(user, today);
            limits.put(FIELD_APP_GEN_COUNT, 0);
            limits.put(FIELD_DOWNLOAD_COUNT, 0);
            limits.put(FIELD_EXPORT_COUNT, 0);
        } else {
            // 获取当前计数
            String appGenStr = hashOps.get(userKey, FIELD_APP_GEN_COUNT);
            String downloadStr = hashOps.get(userKey, FIELD_DOWNLOAD_COUNT);
            String exportStr = hashOps.get(userKey, FIELD_EXPORT_COUNT);

            limits.put(FIELD_APP_GEN_COUNT, parseInt(appGenStr));
            limits.put(FIELD_DOWNLOAD_COUNT, parseInt(downloadStr));
            limits.put(FIELD_EXPORT_COUNT, parseInt(exportStr));
        }

        return limits;
    }

    /**
     * 递增用户特定限制的计数
     */
    private int incrementUserLimit(User user, String fieldName) {
        String userKey = buildUserLimitsKey(user.getId());
        HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();

        // 原子性递增
        Long newCount = hashOps.increment(userKey, fieldName, 1);

        // 设置过期时间（第二天凌晨过期）
        setKeyExpiration(userKey);

        return newCount.intValue();
    }

    /**
     * 重置用户今日限制数据
     */
    private void resetUserDailyLimits(User user, String date) {
        String userKey = buildUserLimitsKey(user.getId());
        HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();

        Map<String, String> resetData = new HashMap<>();
        resetData.put(FIELD_DATE, date);
        resetData.put(FIELD_USER_ROLE, user.getUserRole());
        resetData.put(FIELD_APP_GEN_COUNT, "0");
        resetData.put(FIELD_DOWNLOAD_COUNT, "0");
        resetData.put(FIELD_EXPORT_COUNT, "0");

        hashOps.putAll(userKey, resetData);
        setKeyExpiration(userKey);

        log.info("重置用户 {} 的今日限制数据，日期: {}, 角色: {}", user.getId(), date, user.getUserRole());
    }

    /**
     * 构建用户限制Redis key
     */
    private String buildUserLimitsKey(Long userId) {
        return USER_LIMITS_KEY_PREFIX + userId;
    }

    /**
     * 设置Redis key的过期时间（到明天凌晨）
     */
    private void setKeyExpiration(String key) {
        // 设置25小时过期时间，确保跨越到第二天
        stringRedisTemplate.expire(key, 25, TimeUnit.HOURS);
    }

    /**
     * 安全的字符串转整数
     */
    private int parseInt(String str) {
        try {
            return str != null ? Integer.parseInt(str) : 0;
        } catch (NumberFormatException e) {
            return 0;
        }
    }
}
